home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Freeware / CheckDisk / Src / FFSsupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  17.9 KB  |  555 lines

  1. /*
  2. **    $RCSfile: FFSsupport.c,v $
  3. **    $Filename: FFSsupport.c $
  4. **    $Revision: 0.0 $
  5. **    $Date: $
  6. **
  7. **    Support functions for low-level access to FFS on-disk data structures
  8. **    (version 0.1)
  9. **
  10. **    (C) Copyright 2002 by Etienne Vogt
  11. */
  12.  
  13. #define __USE_SYSBASE
  14. #include <exec/io.h>
  15. #include <dos/dos.h>
  16. #include <devices/newstyle.h>
  17. #include <devices/trackdisk.h>
  18. #include <proto/exec.h>
  19. #include <proto/dos.h>
  20. #include <clib/alib_protos.h>
  21. #include <string.h>
  22. #include "ffs.h"
  23.  
  24. #define    io_HighOffset    io_Actual
  25.  
  26. /* external global variables */
  27.  
  28. extern struct ExecBase *SysBase;
  29. extern struct DosLibrary *DOSBase;
  30. extern struct IOStdReq *DeviceIO;
  31. extern struct DiskDevice mydiskdev;
  32.  
  33. /* internal function prototypes */
  34.  
  35. static int readbitmaptable(ULONG **bitmap, ULONG *bmtable, int off_start, int off_end, ULONG size, ULONG *sizeleft);
  36. static BOOL check64bit(struct IOStdReq *ioreq);
  37. static UBYTE __inline capitalch(UBYTE ch);
  38. static STRPTR __inline hstr2c(UBYTE *hstr);
  39.  
  40. /* initFFS: initialise some fields in DiskDevice structure and check for need and    **
  41. **    availability of 64bit commands.                            **
  42. **    This function must be called before using any other FFSsupport function.    **
  43. **    The exec device must have been properly opened using the DeviceIO IoStdReq    **
  44. **    before calling this function.                            */
  45.  
  46. int initFFS(void)
  47. { ULONG cylsize512;
  48.   int error=0;
  49.  
  50.   mydiskdev.dd_SectorsPerCyl = mydiskdev.dd_SectorsPerTrack * mydiskdev.dd_Surfaces;
  51.   mydiskdev.dd_HighKey = ((mydiskdev.dd_HighCyl - mydiskdev.dd_LowCyl + 1) * mydiskdev.dd_SectorsPerCyl) /
  52.     mydiskdev.dd_SectorsPerBlock - 1;
  53.   mydiskdev.dd_BlockSizeL = mydiskdev.dd_SectorSize * mydiskdev.dd_SectorsPerBlock / 4;
  54.   mydiskdev.dd_RootKey = (mydiskdev.dd_HighKey + mydiskdev.dd_Reserved) / 2;
  55.  
  56.   cylsize512 = mydiskdev.dd_SectorsPerCyl * mydiskdev.dd_SectorSize / 512;
  57.  
  58.   if (mydiskdev.dd_HighCyl * cylsize512 >= 8*1024*1024)
  59.   { if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("initFFS: Partition extends beyond the first 4 Gb of the drive\n");
  60.     if (check64bit(DeviceIO))
  61.     { if (mydiskdev.dd_Flags & DDFF_VERBOSE) PutStr("initFFS: Using NSD 64bit addressing\n\n");
  62.       mydiskdev.dd_Flags |= DDFF_DO64BIT;
  63.     }
  64.     else
  65.     { PutStr("initFFS: 64bit addressing is required but not available\n");
  66.       error = ERROR_OBJECT_TOO_LARGE;
  67.     }
  68.   }
  69.  
  70.   return error;
  71. }
  72.  
  73. static BOOL check64bit(struct IOStdReq *ioreq)
  74. { struct NSDeviceQueryResult *NSDQuery;
  75.   BOOL is64bit=FALSE;
  76.   UWORD *cmdcheck;
  77.  
  78.   if (NSDQuery = (struct NSDeviceQueryResult *)AllocVec(sizeof(struct NSDeviceQueryResult), MEMF_PUBLIC|MEMF_CLEAR))
  79.   { ioreq->io_Command = NSCMD_DEVICEQUERY;
  80.     ioreq->io_Data = NSDQuery;
  81.     ioreq->io_Length = sizeof(struct NSDeviceQueryResult);
  82.     if (!DoIO((struct IORequest *)ioreq) && ioreq->io_Actual >= 16 && ioreq->io_Actual <= sizeof(struct NSDeviceQueryResult)
  83.     && NSDQuery->SizeAvailable == ioreq->io_Actual)
  84.     { if (NSDQuery->DeviceType == NSDEVTYPE_TRACKDISK)
  85.       {    for (cmdcheck = NSDQuery->SupportedCommands ; *cmdcheck ; cmdcheck++)
  86.     { if (*cmdcheck == NSCMD_TD_READ64) is64bit = TRUE;
  87.     }
  88.       }
  89.       else Printf("Not a trackdisk-like device (type %ld)\n", NSDQuery->DeviceType);
  90.     }
  91.     else PutStr("NSCMD_DEVICEQUERY failed !\n");
  92.     FreeVec(NSDQuery);
  93.   }
  94.   else PutStr("No memory for NSDeviceQueryResult structure");
  95.   return is64bit;
  96. }
  97.  
  98. /* readblock: read a block from an FFS partition given by its KeyID number.        **
  99. **    The block is returned as an ULONG * and must be properly FreeVec()ed by the    **
  100. **    caller when no longer needed.                            **
  101. **    NULL is returned in case of an error, with the error code in DeviceIO->io_Error */
  102.  
  103. ULONG *readblock(ULONG KeyID)
  104. { ULONG blocksize = mydiskdev.dd_BlockSizeL * 4;
  105.   ULONG highsects = ((1L << 23) / mydiskdev.dd_SectorSize) * 512;
  106.   ULONG *buffer;
  107.   int error;
  108.  
  109.   if (buffer = AllocVec(blocksize, mydiskdev.dd_BufMemType))
  110.   { DeviceIO->io_Data = buffer;
  111.     DeviceIO->io_Length = blocksize;
  112.     DeviceIO->io_Offset = mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl * mydiskdev.dd_SectorSize +
  113.     KeyID * blocksize;    /* Compute lower 32bits offset */
  114.     if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  115.     { DeviceIO->io_Command = NSCMD_TD_READ64;
  116.       DeviceIO->io_HighOffset = (mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl + KeyID * mydiskdev.dd_SectorsPerBlock) /
  117.     highsects;
  118.     }
  119.     else DeviceIO->io_Command = CMD_READ;
  120.     if (error = DoIO((struct IORequest *)DeviceIO))
  121.     { FreeVec(buffer);
  122.       buffer = NULL;
  123.     }
  124.   }
  125.   else DeviceIO->io_Error = TDERR_NoMem;
  126.   return buffer;
  127. }
  128.  
  129. /* writeblock: write a block back to an FFS partition given by its KeyID number.    **
  130. **    The checksum must have been computed previously with sumblock() if required.    **
  131. **    If the write fails, the error code is returned.                    */
  132.  
  133. int writeblock(ULONG *buffer, ULONG KeyID)
  134. { ULONG blocksize = mydiskdev.dd_BlockSizeL * 4;
  135.   ULONG highsects = ((1L << 23) / mydiskdev.dd_SectorSize) * 512;
  136.  
  137.   DeviceIO->io_Data = buffer;
  138.   DeviceIO->io_Length = blocksize;
  139.   DeviceIO->io_Offset = mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl * mydiskdev.dd_SectorSize +
  140.       KeyID * blocksize;      /* Compute lower 32bits offset */
  141.   if (mydiskdev.dd_Flags & DDFF_DO64BIT)
  142.   { DeviceIO->io_Command = NSCMD_TD_WRITE64;
  143.     DeviceIO->io_HighOffset = (mydiskdev.dd_LowCyl * mydiskdev.dd_SectorsPerCyl + KeyID * mydiskdev.dd_SectorsPerBlock) /
  144.       highsects;
  145.   }
  146.   else DeviceIO->io_Command = CMD_WRITE;
  147.  
  148.   return DoIO((struct IORequest *)DeviceIO);
  149. }
  150.  
  151. /* checkblock: perform basic consistency checks on a filesystem block according to the    **
  152. **    expected types and subtypes. If type and/or subtype are set to 0, the         **
  153. **    corresponding checks are skipped. If type is set to 0, the checksum test is     **
  154. **    also skipped. A non-zero return code is returned in case of failure.        */
  155.  
  156. int checkblock(ULONG *buffer, ULONG KeyID, int type, int sectype)
  157. { ULONG chksum = 0;
  158.   int i;
  159.  
  160.   if (type)
  161.     if (buffer[FILE_TYPE] != type) return ERR_BADTYPE;
  162.   if (type == T_SHORT && sectype)
  163.     if (buffer[mydiskdev.dd_BlockSizeL+FILE_SECTYPE] != sectype) return ERR_BADSECTYPE;
  164.   if ((type == T_SHORT && sectype != ST_ROOT) || type == T_LIST)
  165.     if (buffer[FILE_OWNKEY] != KeyID) return ERR_BLKCORRUPT;
  166.   else if (type == T_SHORT && sectype == ST_ROOT)
  167.     if (buffer[FILE_OWNKEY]) return ERR_BLKCORRUPT;
  168.   if (type)
  169.   { for (i = 0 ; i < mydiskdev.dd_BlockSizeL ; i++) chksum += buffer[i];
  170.     if (chksum) return ERR_BADCHKSUM;
  171.   }
  172.  
  173.   return 0;
  174. }
  175.  
  176. /* checkbmblock: verify the checksum of a bitmap block. ERR_BADCHKSUM is returned in    **
  177. **    case of failure.                                */
  178.  
  179. int checkbmblock(ULONG *buffer)
  180. { ULONG chksum = 0;
  181.   int i;
  182.  
  183.   for (i = 0 ; i < mydiskdev.dd_BlockSizeL ; i++) chksum += buffer[i];
  184.   if (chksum) return ERR_BADCHKSUM;
  185.   else return 0;
  186. }
  187.  
  188. /* readbitmap: read the volume bitmap into memory from the pointers in the volume    **
  189. **    rootblock. The bitmap is returned as an array of ULONG (bit 0 of first ULONG    **
  190. **    is for the first non-reserved block). The array must be FreeVec()ed when no    **
  191. **    longer needed. NULL is returned in case of error.                */
  192.  
  193. ULONG *readbitmap(ULONG *rootblock)
  194. { ULONG bitmapsize = ((mydiskdev.dd_HighKey - mydiskdev.dd_Reserved + 32) / 32) * 4;
  195.   ULONG sizeleft = bitmapsize;
  196.   ULONG bmextkey;
  197.   ULONG *bitmap,*pbitmap,*bitmapext;
  198.   int error;
  199.  
  200.   if (bitmap = AllocVec(bitmapsize, MEMF_ANY))
  201.   { pbitmap = bitmap;
  202.  
  203.     if (error = readbitmaptable(&pbitmap, rootblock, mydiskdev.dd_BlockSizeL+ROOT_BITMAPBLOCKS, mydiskdev.dd_BlockSizeL+ROOT_BITMAPEXT, bitmapsize, &sizeleft))
  204.     { Printf("readbitmap: error %ld\n", error);
  205.       FreeVec(bitmap);
  206.       return NULL;
  207.     }
  208.  
  209.     bmextkey = rootblock[mydiskdev.dd_BlockSizeL+ROOT_BITMAPEXT];
  210.     while (sizeleft)
  211.     { if (bmextkey > mydiskdev.dd_HighKey || bmextkey < mydiskdev.dd_Reserved)
  212.       { Printf("readbitmap: bitmap extension block %lu is out of range\n", bmextkey);
  213.     FreeVec(bitmap);
  214.     return NULL;
  215.       }
  216.       if (bitmapext = readblock(bmextkey))
  217.       { if (error = readbitmaptable(&pbitmap, bitmapext, BEXT_POINTERS, mydiskdev.dd_BlockSizeL+BEXT_EXTENSION, bitmapsize, &sizeleft))
  218.     { Printf("readbitmap: error %ld\n", error);
  219.       FreeVec(bitmapext);
  220.       FreeVec(bitmap);
  221.       return NULL;
  222.     }
  223.     bmextkey = bitmapext[mydiskdev.dd_BlockSizeL+BEXT_EXTENSION];
  224.     FreeVec(bitmapext);
  225.       }
  226.       else
  227.       { Printf("readbitmap: couldn't read bitmap extension block %lu (error %ld)\n", bmextkey, DeviceIO->io_Error);
  228.     FreeVec(bitmap);
  229.     return NULL;
  230.       }
  231.     }
  232.   }
  233.   else Printf("readbitmap: couldn't allocate %lu bytes for bitmap\n", bitmapsize);
  234.  
  235.   return bitmap;
  236. }
  237.  
  238. static int readbitmaptable(ULONG **bitmap, ULONG *bmtable, int off_start, int off_end, ULONG size, ULONG *sizeleft)
  239. { UWORD bmblocksize;
  240.   ULONG *bmblock;
  241.   ULONG bmkey;
  242.   int i, error;
  243.  
  244.   for (i = off_start ; i < off_end ; i++)
  245.   { bmkey = bmtable[i];
  246.     if (bmkey > mydiskdev.dd_HighKey || bmkey < mydiskdev.dd_Reserved)
  247.     { Printf("readbitmap: bitmap block %lu is out of range\n", bmkey);
  248.       return ERR_INVBLKNUM;
  249.     }
  250.     if (bmblock = readblock(bmkey))
  251.     { if (error = checkbmblock(bmblock))
  252.       { Printf("readbitmap: Invalid bitmap block %lu\n", bmkey);
  253.     FreeVec(bmblock);
  254.     return error;
  255.       }
  256.       bmblocksize = 4 * (mydiskdev.dd_BlockSizeL - 1);
  257.       if (bmblocksize > *sizeleft) bmblocksize = *sizeleft;
  258.       CopyMemQuick(&bmblock[BITMAP_BITMAPDATA], *bitmap, bmblocksize);
  259.       *bitmap += bmblocksize / 4;
  260.       *sizeleft -= bmblocksize;
  261.       FreeVec(bmblock);
  262.       if (*sizeleft == 0) break;
  263.     }
  264.     else
  265.     { Printf("readbitmap: Couldn't read bitmap block %lu\n", bmkey);
  266.       return DeviceIO->io_Error;
  267.     }
  268.   }
  269.   return 0;
  270. }
  271.  
  272. /* findfreeblock: Return the KeyID of the first free block found in the in-memory copy    **
  273. **    of the bitmap, starting at StartKey. Zero is returned if all blocks are in use.    */
  274.  
  275. ULONG findfreeblock(ULONG *bitmap, ULONG StartKey)
  276. { ULONG bitmapsizel = (mydiskdev.dd_HighKey - mydiskdev.dd_Reserved + 32) / 32;
  277.   ULONG key=0;
  278.   int startlong, startbit, i, j;
  279.  
  280.   if (StartKey == 0)
  281.   { startlong = 0;
  282.     startbit = 0;
  283.   }
  284.   else
  285.   { startlong = (StartKey - mydiskdev.dd_Reserved) / 32;
  286.     startbit = (StartKey - mydiskdev.dd_Reserved) % 32;
  287.   }
  288.  
  289.   for (i = startlong ; i < bitmapsizel ; i++)
  290.   { if (bitmap[i] == 0) continue;
  291.     else
  292.     { for (j = startbit ; j < 32 ; j++)
  293.       { startbit = 0;
  294.     if ((bitmap[i] & (1L << j)) == 0) continue;
  295.     else
  296.     { key = mydiskdev.dd_Reserved + 32*i + j;
  297.       break;
  298.     }
  299.       }
  300.     }
  301.     if (key) break;
  302.   }
  303.  
  304.   if (key > mydiskdev.dd_HighKey) key = 0;
  305.   return key;
  306. }
  307.  
  308. /* findcontigfreeblocks: Search for a range of n contiguous free blocks in the        **
  309. **    in-memory copy of the bitmap and return the starting KeyID or zero if there are    **
  310. **    not enough contiguous free blocks available.                    */
  311.  
  312. ULONG findcontigfreeblocks(ULONG *bitmap, int numblocks)
  313. { ULONG bitmapsizel = (mydiskdev.dd_HighKey - mydiskdev.dd_Reserved + 32) / 32;
  314.   ULONG StartKey, key=0;
  315.   int startlong, startbit, remain, i, j;
  316.   BOOL skip;
  317.  
  318.   while (StartKey = findfreeblock(bitmap, key))
  319.   { startlong = (StartKey + 1 - mydiskdev.dd_Reserved) / 32;
  320.     startbit = (StartKey + 1 - mydiskdev.dd_Reserved) % 32;
  321.     remain = numblocks - 1;
  322.     skip = FALSE;
  323.  
  324.     for (i = startlong ; i < bitmapsizel ; i++)
  325.     { for (j = startbit ; j < 32 ; j++)
  326.       { startbit = 0;
  327.     if (bitmap[i] & (1L << j)) remain--;
  328.     else
  329.     { skip = TRUE;
  330.       break;
  331.     }
  332.     if (!remain) break;
  333.       }
  334.       if (skip || !remain) break;
  335.     }
  336.  
  337.     if ((key = mydiskdev.dd_Reserved + 32*i + j) > mydiskdev.dd_HighKey)
  338.     { StartKey = 0;
  339.       break;
  340.     }
  341.     if (!remain) break;
  342.   }
  343.  
  344.   return StartKey;
  345. }
  346.  
  347. /* allocblock: Mark a block as allocated in the on-memory bitmap and return its        **
  348. **    previous state (TRUE = free). Updating the on-disk bitmap is best left to the    **
  349. **    disk validator once all low-level changes are done.                */
  350.  
  351. BOOL allocblock(ULONG *bitmap, ULONG KeyID)
  352. { int bmlong = (KeyID - mydiskdev.dd_Reserved) / 32;
  353.   int bmbit = (KeyID - mydiskdev.dd_Reserved) % 32;
  354.   BOOL wasfree;
  355.  
  356.   if (bitmap[bmlong] & (1L << bmbit)) wasfree = TRUE;
  357.   else wasfree = FALSE;
  358.  
  359.   bitmap[bmlong] &= ~(1L << bmbit);
  360.  
  361.   return wasfree;
  362. }
  363.  
  364. /* freeblock: Mark a block as free in the on-memory bitmap and return its previous    **
  365. **    state (TRUE = free). Updating the on-disk bitmap is best left to the disk    **
  366. **    validator once all low-level changes are done.                    */
  367.  
  368. BOOL freeblock(ULONG *bitmap, ULONG KeyID)
  369. { int bmlong = (KeyID - mydiskdev.dd_Reserved) / 32;
  370.   int bmbit = (KeyID - mydiskdev.dd_Reserved) % 32;
  371.   BOOL wasfree;
  372.  
  373.   if (bitmap[bmlong] & (1L << bmbit)) wasfree = TRUE;
  374.   else wasfree = FALSE;
  375.  
  376.   bitmap[bmlong] |= (1L << bmbit);
  377.  
  378.   return wasfree;
  379. }
  380.  
  381. /* isfreeblock: Check if a given block is marked as free in the in-memory bitmap.    */
  382.  
  383. BOOL isfreeblock(ULONG *bitmap, ULONG KeyID)
  384. { int bmlong = (KeyID - mydiskdev.dd_Reserved) / 32;
  385.   int bmbit = (KeyID - mydiskdev.dd_Reserved) % 32;
  386.  
  387.   if (bitmap[bmlong] & (1L << bmbit)) return TRUE;
  388.   else return FALSE;
  389. }
  390.  
  391. /* initheader: Initializes a file header in memory with given KeyID, ParentKey, type,    **
  392. **    subtype and name (all other fields will be zero). Returns a pointer to the    **
  393. **    initialized block or NULL for failure.                        **
  394. **    The block MUST be checksummed with sumblock() before being written back to disk */
  395.  
  396. ULONG *initheader(ULONG KeyId, ULONG ParentKey, int type, int sectype, STRPTR name)
  397. { ULONG blocksize = mydiskdev.dd_BlockSizeL * 4;
  398.   ULONG *header;
  399.   BYTE namelen, *nameptr;
  400.  
  401.   if (header = AllocVec(blocksize, mydiskdev.dd_BufMemType|MEMF_CLEAR))
  402.   { header[FILE_TYPE] = type;
  403.     header[mydiskdev.dd_BlockSizeL+FILE_SECTYPE] = sectype;
  404.     if ((type == T_SHORT && sectype != ST_ROOT) || type == T_LIST)
  405.     { header[FILE_OWNKEY] = KeyId;
  406.       header[mydiskdev.dd_BlockSizeL+FILE_PARENT] = ParentKey;
  407.     }
  408.     if (type == T_SHORT && name)
  409.     { namelen = strlen(name);
  410.       if (namelen > 30) namelen = 30;
  411.       nameptr = (UBYTE *)&header[mydiskdev.dd_BlockSizeL+FILE_NAME];
  412.       nameptr[0] = namelen;
  413.       strncpy(&nameptr[1], name, 30);
  414.     }
  415.   }
  416.  
  417.   return header;
  418. }
  419.  
  420. /* clearblockptrs: clear the block pointers in a file header or file extension block    */
  421.  
  422. void clearblockptrs(ULONG *header)
  423. { int i;
  424.  
  425.   header[FILE_BLOCKCOUNT] = 0;
  426.   header[FILE_FIRSTBLOCK] = 0;
  427.   for (i = mydiskdev.dd_BlockSizeL+FILE_DATABLOCK1 ; i >= FILE_DATABLOCKS ; i--) header[i] = 0;
  428. }
  429.  
  430. /* sumblock: compute an FFS metadata block checksum so the block can be written back to    **
  431. **    disk.                                        */
  432.  
  433. void sumblock(ULONG *buffer)
  434. { ULONG chksum=0;
  435.   int i;
  436.  
  437.   buffer[FILE_CHECKSUM] = 0;
  438.   for (i = 0 ; i < mydiskdev.dd_BlockSizeL ; i++) chksum += buffer[i];
  439.   buffer[FILE_CHECKSUM] = -chksum;
  440. }
  441.  
  442. /* hashname: compute the hash index relative to the start of the directory block for    **
  443. **    the given file name                                */
  444.  
  445. ULONG hashname(STRPTR name)
  446. { ULONG hash = strlen(name);
  447.  
  448.   while (*name)
  449.     hash = (hash * 13 + capitalch(*name++)) & 0x7ff;
  450.  
  451.   return hash % (mydiskdev.dd_BlockSizeL - 56) + UDIR_HASHTABLE;
  452. }
  453.  
  454. static UBYTE __inline capitalch(UBYTE ch)
  455. { if ((mydiskdev.dd_DOSType & 0xff) < 2)
  456.     return (UBYTE)(ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch);
  457.   else
  458.     return (UBYTE)(ch >= '\340' && ch <= '\376' && ch != '\367' ||
  459.     ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch);
  460. }
  461.  
  462. /* gethashchain: return the hash chain pointer needed for inserting a given header into    **
  463. **    a given directory block. Since 0 is a valid result, (ULONG)(-1) is returned to    **
  464. **    indicate an error. Check explicitely for this value for an error !        **
  465. **    Assumes the hash chain is correctly sorted by ascending key ID as must be the    **
  466. **    case with FFS (for OFS it doesn't really matter so we do as if it was FFS).    */
  467.  
  468. ULONG gethashchain(ULONG *dirblock, ULONG *headerblock)
  469. { ULONG hash = hashname(hstr2c((UBYTE *)&headerblock[mydiskdev.dd_BlockSizeL+FILE_NAME]));
  470.   ULONG key;
  471.   ULONG *block;
  472.   int error;
  473.  
  474.   if ((key = dirblock[hash]) == 0) return 0;
  475.   else
  476.   { while (headerblock[FILE_OWNKEY] > key)
  477.     { if (block = readblock(key))
  478.       { if (error = checkblock(block, key, T_SHORT, 0))
  479.     { Printf("gethashchain: Invalid header block %lu (error %ld)\n", key, error);
  480.       FreeVec(block);
  481.       return (ULONG)(-1L);
  482.     }
  483.     key = block[mydiskdev.dd_BlockSizeL+FILE_HASHCHAIN];
  484.     FreeVec(block);
  485.       }
  486.       else
  487.       { Printf("gethashchain: Couldn't read header block %lu (error %ld)\n", key, DeviceIO->io_Error);
  488.     return (ULONG)(-1L);
  489.       }
  490.     }
  491.   }
  492.  
  493.   return key;
  494. }
  495.  
  496. /* hashlink: link a given header into a directory hash chain. The header should be     **
  497. **    valid, in particular, its hashchain pointer should be set via a previous call    **
  498. **    to gethashchain() and it should have been written back to disk via writeblock()    **
  499. **    so that the risk of disk structure corruption is minimized.            */
  500.  
  501. int hashlink(ULONG *dirblock, ULONG *headerblock)
  502. { ULONG hash = hashname(hstr2c((UBYTE *)&headerblock[mydiskdev.dd_BlockSizeL+FILE_NAME]));
  503.   ULONG key, headerkey = headerblock[FILE_OWNKEY];
  504.   ULONG *block;
  505.   int error;
  506.  
  507.   if ((key = dirblock[hash]) == 0 || key > headerkey) dirblock[hash] = headerkey;
  508.   else
  509.   { while (key)
  510.     { if (block = readblock(key))
  511.       { if (error = checkblock(block, key, T_SHORT, 0))
  512.     { Printf("hashlink: Invalid header block %lu (error %ld)\n", key, error);
  513.       FreeVec(block);
  514.       return error;
  515.     }
  516.     if ((key = block[mydiskdev.dd_BlockSizeL+FILE_HASHCHAIN]) > headerkey) break;
  517.       }
  518.       else
  519.       { Printf("hashlink: Couldn't read header block %lu (error %ld)\n", key, DeviceIO->io_Error);
  520.     return DeviceIO->io_Error;
  521.       }
  522.     }
  523.     block[mydiskdev.dd_BlockSizeL+FILE_HASHCHAIN] = headerkey;
  524.     sumblock(block);
  525.     if (error = writeblock(block, block[FILE_OWNKEY]))
  526.     { Printf("hashlink: Couldn't write header block %lu (error %ld)\n", block[FILE_OWNKEY], error);
  527.       FreeVec(block);
  528.       return error;
  529.     }
  530.     FreeVec(block);
  531.   }
  532.  
  533.   DateStamp((struct DateStamp *)&dirblock[mydiskdev.dd_BlockSizeL+UDIR_DAYS]);
  534.   sumblock(dirblock);
  535.  
  536.   if ((key = dirblock[UDIR_OWNKEY]) == 0) key = mydiskdev.dd_RootKey;
  537.  
  538.   if (error = writeblock(dirblock, key))
  539.   { Printf("hashlink: Couldn't write directory block %lu (error %ld)\n", key, error);
  540.     return error;
  541.   }
  542.  
  543.   return 0;
  544. }
  545.  
  546. static STRPTR __inline hstr2c(UBYTE *hstr)
  547. { static char buffer[256];
  548.   int n;
  549.  
  550.   if ((n = *hstr++) == 0) return NULL;
  551.   strncpy(buffer, hstr, n);
  552.   buffer[n] = 0;
  553.   return buffer;
  554. }
  555.